#ifndef CSUPBR_PRIMITIVE_H
#define CSUPBR_PRIMITIVE_H

#include "transform.h"
#include "pbrmath.h"

namespace csupbr {

    struct GeoPrimitive;

    struct Intersection {
        // hitting point
        Point3f pHit;

        // Geometry Normal, Shading Normal
        Normal geoN, shN;

        // uv coord
        Vec2f uv;

        // animation time
        Float time;
        
        // Geometry Coordinate, Shading Coordinate
        CoordinateSystem geoCoord, shCoord;

        GeoPrimitive* primitive;

        void newRay(Ray &r, const Vec3f &d) const {
            r = Ray(pHit + d * r.mint, d);
        }

        Ray newRay(const Vec3f &d) const {
            Ray ret(pHit, d);
            ret.origin += ret.direct * ret.mint;
            return ret;
        }
        
    };

    /**
     * Intersected Primitive
     */
    struct Primitive {
        virtual bool intersect(const Ray &ray, Intersection &isct) const = 0;
        virtual bool intersectP(const Ray &ray, bool blend_test) const = 0;
        virtual BBox3f getBBox() const = 0;
    };

    struct Shape;
    struct Material;

    /**
     * Geometry Primitive
     */
    struct GeoPrimitive : public Primitive {
        GeoPrimitive(std::shared_ptr<Shape> shape, std::shared_ptr<Material> material);
        bool intersect(const Ray &ray, Intersection &isct) const override;
        bool intersectP(const Ray &ray, bool blend_test) const override;
        BBox3f getBBox() const override;

        std::shared_ptr<Shape> shape;
        std::shared_ptr<Material> material;
    };

}

#endif // !CSUPBR_PRIMITIVE_H